/**
* Copyright (C) 2018-2020
* All rights reserved, Designed By www.yixiang.co
* 注意：
* 本软件为www.yixiang.co开发研制，未经购买不得使用
* 购买后可获得全部源代码（禁止转卖、分享、上传到码云、github等开源平台）
* 一经发现盗用、分享等行为，将追究法律责任，后果自负
*/
package co.yixiang.mall.biz.mallsetting.service.impl;

import co.yixiang.common.core.utils.StringUtils;
import co.yixiang.common.mproot.common.service.impl.BaseServiceImpl;
import co.yixiang.common.mproot.domain.PageResult;

import co.yixiang.mall.biz.freeze.service.TbUserRebateFreezeService;
import co.yixiang.mall.biz.mallsetting.mapper.TbBrokerageFreezeMapper;
import co.yixiang.mall.biz.mallsetting.mapper.YxGradationMapper;
import co.yixiang.mall.biz.mallsetting.service.TbBrokerageFreezeService;
import co.yixiang.mall.biz.order.service.YxStoreOrderService;
import co.yixiang.mall.biz.user.mapper.YxUserRewardCalculationMapper;
import co.yixiang.mall.common.mall.dto.YxCommissionCalculateRatioDto;
import co.yixiang.mall.common.mall.dto.YxUserParentLevelDto;
import co.yixiang.mall.common.mallsetting.domain.TbBrokerageFreeze;
import co.yixiang.mall.common.mallsetting.domain.YxGradation;

import co.yixiang.mall.common.order.domain.TbUserRebateFreeze;
import co.yixiang.mall.common.order.dto.YxStoreOrderDto;
import lombok.AllArgsConstructor;
import co.yixiang.mall.biz.mallsetting.service.YxGradationService;
import co.yixiang.mall.common.mallsetting.dto.YxGradationDto;
import co.yixiang.mall.common.mallsetting.dto.YxGradationQueryCriteria;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
// 默认不使用缓存
//import org.springframework.cache.annotation.CacheConfig;
//import org.springframework.cache.annotation.CacheEvict;
//import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Pageable;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.util.*;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;

/**
* @author fanwnejie
* @date 2021-03-17
*/
@Service
@AllArgsConstructor
@NoArgsConstructor
//@CacheConfig(cacheNames = "yxGradation")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class YxGradationServiceImpl extends BaseServiceImpl<YxGradationMapper, YxGradation> implements YxGradationService {

    // 级差 平级奖励 使用数据查询
    @Autowired
    YxUserRewardCalculationMapper yxUserRewardCalculationMapper;
    //订单查询
    @Autowired
    YxStoreOrderService yxStoreOrderService;
    //佣金统计计算表Service
    @Autowired
    TbBrokerageFreezeService tbBrokerageFreezeService;
    //佣金统计计算表Mapper
    @Autowired
    TbBrokerageFreezeMapper tbBrokerageFreezeMapper;
    //佣金冻结表 Service
    @Autowired
    TbUserRebateFreezeService tbUserRebateFreezeService;

    @Override
    public PageResult<YxGradationDto> queryAll(YxGradationQueryCriteria criteria, Pageable pageable) {
        return null;
    }

    @Override
    public List<YxGradation> queryAll(YxGradationQueryCriteria criteria) {
        return null;
    }

    @Override
    public void download(List<YxGradationDto> all, HttpServletResponse response) throws IOException {

    }

    /**
     *  级差和平级奖励计算数据准备
     * @param orderDto
     * @param level
     * @param startTimestamp
     * @param endTimestamp
     * @return
     */
    public Boolean gradationCalculate(YxStoreOrderDto orderDto, Integer level, Timestamp startTimestamp, Timestamp endTimestamp) {
        //冻结表数据准备
        Map<String,Object> freezeTable = new HashMap<>();
        //冻结开始时间
        freezeTable.put("startTime",startTimestamp);
        //冻结结束时间
        freezeTable.put("endTime",endTimestamp);
        //订单id
        freezeTable.put("orderID",orderDto.getOrderId());
        //用户id
        Long uid = orderDto.getUid();
        // 各项佣金比例
        List<YxCommissionCalculateRatioDto> calculateRatioDtoList = yxUserRewardCalculationMapper.queryAllLevelRebateRatio();
        // 有平级奖励等级
        List<Map<String,Object>> peersList = new ArrayList<>();
        // 所有的等级的返佣比例
        Map<String, BigDecimal> commissionRatioMap = new HashMap<>();
        // 各等级的月扣除金额封顶
        Map<Integer, BigDecimal> cappingMap = new HashMap<>();
        // 各项佣金比例存储
        for (int i = 0; i<calculateRatioDtoList.size(); i++){
            YxCommissionCalculateRatioDto yccrDto = calculateRatioDtoList.get(i);
            // 所有等级返佣比例
            commissionRatioMap.put(yccrDto.getGrade().toString(),yccrDto.getCommissionRatio());
            //各等级的月扣除金额封顶数据
            cappingMap.put(yccrDto.getGrade(),yccrDto.getCapping());
            //平级奖励的数据
            if(StringUtils.isNotEmpty(yccrDto.getGeneration()) ){
                Map<String,Object> peersMap = new HashMap<>();
                //平级返佣代数
                peersMap.put("generation",yccrDto.getGeneration());
                //平级返佣标识(1按比率 2均分)
                peersMap.put("type",yccrDto.getType());
                //平级返佣比率
                peersMap.put("rebate",yccrDto.getRebate());
                //月复销封顶金额
                peersMap.put("capping",yccrDto.getCapping());
                //等级
                peersMap.put("grade",yccrDto.getGrade());
                peersList.add(peersMap);
            }
        }
        //用户的推荐人及以上推荐人获取
        List<YxUserParentLevelDto> yxUserParentLevelDtoList = yxUserRewardCalculationMapper.queryParentLevel(uid.intValue());
        //排序
        yxUserParentLevelDtoList.sort((YxUserParentLevelDto yxu1, YxUserParentLevelDto yxu2) -> yxu1.getRownumber().compareTo(yxu2.getRownumber()));

        return  lateralRewardCalculation(peersList,yxUserParentLevelDtoList,commissionRatioMap,level,orderDto.getConsumptionResults(),cappingMap,freezeTable);
    }

    /**
     *  级差佣金 平级奖励佣金计算
     * @param peersList   有平级奖励等级
     * @param yxUserParentLevelDtoList  用户的推荐人及以上推荐人
     * @param commissionRatioMap 所有的等级的返佣比例
     * @param level 订单用户等级
     * @param money 这一单产生的复消业绩(复消业绩 =实付金额*PV值)
     * @param cappingMap 对应等级每月扣除金额的封顶
     * @param freezeTable 冻结表数据准备
     * @return
     */
    public Boolean lateralRewardCalculation(List<Map<String, Object>> peersList,
                                            List<YxUserParentLevelDto> yxUserParentLevelDtoList,
                                            Map<String, BigDecimal> commissionRatioMap,
                                            Integer level, BigDecimal money,
                                            Map<Integer, BigDecimal> cappingMap, Map<String, Object> freezeTable){
        // 平级开始
        int lateralStart = 0;
        // 平级奖励计数
        int lateralNum =0;
        //代数记录
        int generationRecord = 0;
        // 最低平级奖励等级
        Integer lateralLowestLevel = (Integer) peersList.get(0).get("grade");
        //判断当前用户是否平级奖励等级
        if(lateralLowestLevel <= level){
            lateralStart=1;
        }
        // 级差用户数据
        List<Map<Integer,BigDecimal>> gradationList = new ArrayList<>();
        // 平级用户数据
        List<Map<Integer,BigDecimal>> lateralList = new ArrayList<>();
        // 本单佣金获取用户记录
        Map<Integer,Integer> userLevel = new HashMap<>();
        // 级差和平级奖励计算开始
        for (int x = 0 ; x <yxUserParentLevelDtoList.size();x++){
            // 级差计算结果
            Map<Integer,BigDecimal> gradationMap = new HashMap<>();
            // 平级计算结果
            Map<Integer,BigDecimal> lateralMap = new HashMap<>();
            // 推荐等级获取
            YxUserParentLevelDto levelDto = yxUserParentLevelDtoList.get(x);
            Integer parentLevel = levelDto.getLevel();
            // 级差计算
            if(level < parentLevel){
                // 相应等级的返佣比例获取
                BigDecimal ratio = commissionRatioMap.get(level.toString());
                // 推荐等级返佣比例获取
                BigDecimal parentRatio = commissionRatioMap.get(parentLevel.toString());
                // 等级之间的返佣比例级差计算
                BigDecimal subtract = parentRatio.subtract(ratio);
                // 级差佣金
                BigDecimal gradationAward = money.multiply(subtract);
                // 级差奖励添加
                gradationMap.put(levelDto.getUid(),gradationAward);
                //用户对用等级数据添加
                userLevel.put(levelDto.getUid(),parentLevel);
                gradationList.add(gradationMap);
                //替换当前等级
                level=parentLevel;
                // 判断推荐是否够平级奖励等级
                if(lateralStart==0 && parentLevel >= lateralLowestLevel){
                    lateralStart=1;
                    continue;
                }
            }
            // 平级计算
            if (lateralLowestLevel <= parentLevel && lateralStart>0 ){
                //每级别等级平级奖励数据
                Map<String,Object> lateralMapRatio = peersList.get(lateralNum);
                //平级奖励返佣比例类型
                String type = (String) lateralMapRatio.get("type");
                // 平级奖励代数
                Integer generation = Integer.parseInt((String) lateralMapRatio.get("generation"));
                // 每代比例不一样（按比例）
                if("1".equals(type)){
                    //平级返佣比率
                    String rebate = (String) lateralMapRatio.get("rebate");
                    // 不同代数个比例获取
                    String[] lateralRatio = rebate.split(",");
                    // 每代平级奖励佣金比例
                    BigDecimal rebateNum =new BigDecimal(lateralRatio[generationRecord]);
                    //平级佣金
                    BigDecimal lateralAward = money.multiply(rebateNum);
                    //平级用户数据添加
                    lateralMap.put(levelDto.getUid(),lateralAward);
                    //用户对用等级数据添加
                    userLevel.put(levelDto.getUid(),parentLevel);
                    generationRecord++;
                    if (generationRecord==generation){
                        lateralNum++;
                        lateralLowestLevel = (Integer) peersList.get(lateralNum).get("grade");
                    }
                }
                // 每代比例一样（平均）
                if ("2".equals(type)){
                    //平级返佣比率
                    String rebate = (String) lateralMapRatio.get("rebate");
                    if(generation<=generation){
                        //佣金比例
                        BigDecimal rebateNum = new BigDecimal(rebate);
                        //平级佣金
                        BigDecimal lateralAwardAverage = money.multiply(rebateNum);
                        ////平级用户数据添加
                        lateralMap.put(levelDto.getUid(),lateralAwardAverage);
                        //用户对用等级数据添加
                        userLevel.put(levelDto.getUid(),parentLevel);
                    }
                }
                // 替换当前等级
                level= parentLevel;
                lateralList.add(lateralMap);
            }
        }
        Boolean aBoolean = freezeBrokerage(gradationList, lateralList, cappingMap, userLevel,freezeTable);

        return aBoolean ;
    }
    /**
     * 级差佣金 平级奖励佣金冻结
     * @param gradationList 级差用户数据
     * @param lateralList 平级奖励用户数据
     * @param cappingMap 对应等级每月扣除金额
     * @param userLevel 这一单所有获取佣金的用户
     * @param freezeTable 冻结数据
     */
    public Boolean freezeBrokerage(List<Map<Integer, BigDecimal>> gradationList,
                                   List<Map<Integer, BigDecimal>> lateralList,
                                   Map<Integer, BigDecimal> cappingMap,
                                   Map<Integer, Integer> userLevel, Map<String, Object> freezeTable){
        //冻结表中得数据
        List<TbUserRebateFreeze> tbUserRebateFreezeList = new ArrayList<>();
        //级差数据存储
        if(gradationList.size()>0){
            for (Map<Integer,BigDecimal> gradationMap:gradationList){
                for(Integer key :gradationMap.keySet()){
                    Integer level = userLevel.get(key);
                    BigDecimal cappingMoney = cappingMap.get(level);
                    TbUserRebateFreeze tbUserRebateFreeze = selectIntegral(key, gradationMap.get(key), "2", cappingMoney,freezeTable);
                    //冻结佣金类型
                    tbUserRebateFreeze.setCommissionType("2");
                    tbUserRebateFreezeList.add(tbUserRebateFreeze);
                }
            }
        }
        //平级数据存储
        if (lateralList.size()>0){
            for (Map<Integer,BigDecimal> lateralMap:lateralList){
                for(Integer key :lateralMap.keySet()){
                    Integer level = userLevel.get(key);
                    BigDecimal cappingMoney = cappingMap.get(level);
                    TbUserRebateFreeze tbUserRebateFreeze = selectIntegral(key, lateralMap.get(key), "3", cappingMoney, freezeTable);
                    //冻结佣金类型
                    tbUserRebateFreeze.setCommissionType("3");
                    tbUserRebateFreezeList.add(tbUserRebateFreeze);
                }
            }
        }
        boolean saveBatch = tbUserRebateFreezeService.saveBatch(tbUserRebateFreezeList);
        return saveBatch;
    }

    /**
     *  冻结积分 计算
     * @param uid 用户id
     * @param money 佣金
     * @param type 佣金类型
     * @param cappingMoney 用户等级每月扣除金额上限
     * @param freezeTable
     *
     */
    public TbUserRebateFreeze  selectIntegral(Integer uid, BigDecimal money, String type, BigDecimal cappingMoney, Map<String, Object> freezeTable){
        TbUserRebateFreeze tbUserRebateFreeze = new TbUserRebateFreeze();
        // 用户id
        tbUserRebateFreeze.setUserId(uid);
        //冻结状态
        tbUserRebateFreeze.setState(1);
        //冻结开始时间
        tbUserRebateFreeze.setStartTime((Timestamp) freezeTable.get("startTime"));
        //冻结结束时间
        tbUserRebateFreeze.setEndTime((Timestamp) freezeTable.get("endTime"));
        //订单id
        tbUserRebateFreeze.setOrderId(Integer.parseInt((String) freezeTable.get("orderID")));
        // 每笔佣金扣除的钱
        BigDecimal zeroPointOne =new BigDecimal("0.1");
        // 每笔佣金扣除钱返的积分
        BigDecimal onePointFive =new BigDecimal("1.5");
        //用户已经冻结积分
        BigDecimal integralRecord =new BigDecimal("0");
        //用户佣金统计计算表数据
        List<TbBrokerageFreeze> tbBrokerageFreezeList = tbBrokerageFreezeService.lambdaQuery().eq(TbBrokerageFreeze::getUid, uid).eq(TbBrokerageFreeze::getClearing,0).list();
        //有无佣金记录
        if(tbBrokerageFreezeList.size()>0){
        /*本月有佣金记录*/
            // 更新之前级差佣金
            BigDecimal gradationOld = new BigDecimal("0");
            // 更新之前平级奖励佣金
            BigDecimal levelRewardOdl = new BigDecimal("0");
            //更新之前冻结积分
            BigDecimal integralRecordOld = new BigDecimal("0");
            // 冻结积分
            for (TbBrokerageFreeze tbf : tbBrokerageFreezeList){
                integralRecord = integralRecord.add(tbf.getFreezingIntegral());
                if(tbf.getFrozenState()==0){
                    gradationOld = tbf.getGradation();
                    levelRewardOdl = tbf.getLevelReward();
                    integralRecordOld = tbf.getFreezingIntegral();

                }
            }
            // 扣除的金额
            BigDecimal deductMoney = integralRecord.divide(onePointFive,2, RoundingMode.HALF_UP);

            // 判断是否到达上限
            if(deductMoney.compareTo(cappingMoney)==0){
            /*到达扣除上限*/
                //判断佣金类型 2:级差 3:平级
                switch (type){
                    case "2":
                        // 级差佣金
                        tbBrokerageFreezeService.lambdaUpdate() .eq(TbBrokerageFreeze::getUid,uid)
                                                                .eq(TbBrokerageFreeze::getClearing,0)
                                                                .eq(TbBrokerageFreeze::getFrozenState,0)
                                                                .set(TbBrokerageFreeze::getGradation,money.add(gradationOld)).update();
                        //佣金冻结表数据添加
                        //冻结金额
                        tbUserRebateFreeze.setMoney(money.add(gradationOld));
                        // 冻结佣金类型
                        tbUserRebateFreeze.setCommissionType("2");
                        //冻结积分
                        tbUserRebateFreeze.setScore(new BigDecimal("0"));
                    break;
                    case "3":
                        // 平级佣金
                        tbBrokerageFreezeService.lambdaUpdate() .eq(TbBrokerageFreeze::getUid,uid)
                                                                .eq(TbBrokerageFreeze::getClearing,0)
                                                                .eq(TbBrokerageFreeze::getFrozenState,0)
                                                                .set(TbBrokerageFreeze::getLevelReward,money.add(levelRewardOdl)).update();
                        //佣金冻结表数据添加
                        //冻结金额
                        tbUserRebateFreeze.setMoney(money.add(levelRewardOdl));
                        //冻结积分
                        tbUserRebateFreeze.setScore(new BigDecimal("0"));
                        break;
                }
            }else{
            /*未到达空出上限*/
                // 还要扣多少钱到扣除金额的封顶金额
                BigDecimal lackMoney= cappingMoney.subtract(deductMoney).divide(zeroPointOne,2, RoundingMode.HALF_UP);
                // 积分扣除的金额
                BigDecimal deduct = money.multiply(zeroPointOne);
                // 扣除积分金额后的冻结佣金
                BigDecimal freezeMoney = money.subtract(deduct);
                // 冻结积分
                BigDecimal  integral = deduct.multiply(onePointFive).add(integralRecordOld);
                if(lackMoney.compareTo(money)== -1){
                    // 还要扣除的钱小于获利佣金时 需要把不需要扣除的钱计算出来
                     freezeMoney = money.subtract(lackMoney);
                    deduct =  lackMoney.multiply(zeroPointOne);
                    integral = deduct.multiply(onePointFive).add(integralRecordOld);
                }
                //判断佣金类型 2:级差 3:平级
                switch (type){
                    case "2":
                        // 级差佣金
                        tbBrokerageFreezeService.lambdaUpdate() .eq(TbBrokerageFreeze::getUid,uid)
                                                                .eq(TbBrokerageFreeze::getClearing,0)
                                                                .eq(TbBrokerageFreeze::getFrozenState,0)
                                                                .set(TbBrokerageFreeze::getGradation,freezeMoney.add(gradationOld))
                                                                .set(TbBrokerageFreeze::getFreezingIntegral,integral).update();
                        //佣金冻结表数据添加
                        //冻结金额
                        tbUserRebateFreeze.setMoney(freezeMoney.add(gradationOld));
                        //冻结积分
                        tbUserRebateFreeze.setScore(integral);
                        break;
                    case "3":
                        // 平级佣金
                        tbBrokerageFreezeService.lambdaUpdate() .eq(TbBrokerageFreeze::getUid,uid)
                                                                .eq(TbBrokerageFreeze::getClearing,0)
                                                                .eq(TbBrokerageFreeze::getFrozenState,0)
                                                                .set(TbBrokerageFreeze::getLevelReward,freezeMoney.add(levelRewardOdl))
                                                                .set(TbBrokerageFreeze::getFreezingIntegral,integral).update();
                        //佣金冻结表数据添加
                        //冻结金额
                        tbUserRebateFreeze.setMoney(freezeMoney.add(levelRewardOdl));
                        //冻结积分
                        tbUserRebateFreeze.setScore(integral);
                        break;
                }
            }
        }else {
        /*本月无佣金记录*/
            TbBrokerageFreeze tbBrokerageFreeze = new TbBrokerageFreeze();
            // 用户id
            tbBrokerageFreeze.setUid(uid.longValue());
            //结算状态
            tbBrokerageFreeze.setClearing(0);
            //冻结状态
            tbBrokerageFreeze.setFrozenState(0);
            // 积分扣除的计算
            BigDecimal deductMoney = money.multiply(zeroPointOne);
            // 扣完积分的冻结佣金
            BigDecimal freezeMoney = money.subtract(deductMoney);
            // 冻结积分
            BigDecimal  integral = deductMoney.multiply(onePointFive);
            //判断佣金类型 1:自购返利 2:级差 3:平级
            switch (type){
                case "1":
                    tbBrokerageFreeze.setBuyRebate(freezeMoney);
                    break;
                case "2":
                    // 佣金统计表数据添加
                    tbBrokerageFreeze.setGradation(freezeMoney);
                    // 佣金冻结表数据添加
                    tbUserRebateFreeze.setMoney(freezeMoney);
                    break;
                case "3":
                    // 佣金统计表数据添加
                    tbBrokerageFreeze.setLevelReward(freezeMoney);
                    // 佣金冻结表数据添加
                    tbUserRebateFreeze.setMoney(freezeMoney);
                    break;
            }
            // 冻结表中的数据
            tbUserRebateFreeze.setScore(integral);
            //佣金统计表中冻结积分
            tbBrokerageFreeze.setFreezingIntegral(integral);
            tbBrokerageFreezeMapper.insert(tbBrokerageFreeze);

        }
        return tbUserRebateFreeze;
    }

}
